﻿using Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Configuration;
using SdmxMl.Common;
using SdmxMl.GenericMetadata;
using SdmxMl.Manager;
using SdmxMl.Structure;
using System;

namespace Ch.Admin.Bfs.Sms.Sdmx.Extension.CodeBook.Meta
{
    public class BookProvider : BaseMetaProvider
    {
        #region Constants 

        public const string TARGET_BOOK = "TG_ACTIVITY";
        public const string BOOK_REPORT_ID = "R_BOOK_GEN";
        public const string MSD_BOOK_GEN_ID = "MSD_BOOK_GENERATOR";
        public const string MSD_BOOK_GEN_AGENCY = "CH1_SMS";
        public const string MSD_BOOK_REPORT_MODULE = "MODULES";
        public const string MSD_BOOK_REPORT_TYPE = "TYPE";
        public const string MSD_BOOK_REPORT_IDENT = "IDENT";
        public const string MSD_BOOK_REPORT_CFG = "CONFIG";

        #endregion

        #region Internal members

        /// <summary> Loader, container for SDMX artefacts </summary>
        private MetadataSetType metaSet;
        private MetadataStructureDefinitionType msd;
        private ReportStructureType report;

        #endregion

        #region Constructor

        public BookProvider(string lang, string metaFullId, BookConfiguration cfg)
            : base(lang, metaFullId, cfg)
        {
            try
            {
                // Get metadataset (DDI like)
                ArtefactRefTyped art = new ArtefactRefTyped(SdmxArtefactType.MetadataSet, fullIdKey);
                //ensure to refresh cache
                sm = ReferenceManager.GetSmContainerImage();
                metaSet = sm.GetArtefact(art.Type, art, true)  as SdmxMl.GenericMetadata.MetadataSetType;

                // Get MSD
                if (metaSet.MetadataStructureRef.Id != MSD_BOOK_GEN_ID)
                    throw new ApplicationException("Invalid metaset, not adapted to Book generation");

                sm.LoadMissingArtefactsFromRegistry(metaSet.MetadataStructureRef);
                msd = sm.GetArtefact(metaSet.MetadataStructureRef) as MetadataStructureDefinitionType;
                report = msd.ReportStructureList.LocateItem(metaSet.ReportRef);

                if (report.Id != BOOK_REPORT_ID)
                    throw new ApplicationException("Invalid metaset, Report id not adapted to Book generation");

                GetOverviewHierarchy();
            }
            catch (Exception ex)
            {
                throw ex is ApplicationException ? ex : new ApplicationException("Unable to obtain Book composition metadata with " + fullIdKey, ex);
            }
        }

        private void GetOverviewHierarchy()
        {
            // We have only one row
            AttributeValueSetType atv = metaSet.AttributeValueSetList[0];
            hierarchy = new Hierarchy();

            //We expect at least the module list of reportedAttributes
            if (atv.ReportedAttributeList.Count < 1)
                throw new ApplicationException("Invalid Domains count for Codebook generation");

            // create Root and two domains children
            BookHierarchy bookHierarchy = new BookHierarchy(metaSet.FullIdent, false);

            ReportedAttributeTypeList repList = new ReportedAttributeTypeList();
            atv.ReportedAttributeList.GetReportedAttributeListForConcept(MSD_BOOK_REPORT_MODULE, repList);
            foreach (ReportedAttributeType rep in repList)
            {
                TableOfContents moduletype = GetModuleType(rep.ReportedAttributeList.GetReportedAttributeOfConcept(MSD_BOOK_REPORT_TYPE).Value.ToString());
                string identity = rep.ReportedAttributeList.GetReportedAttributeOfConcept(MSD_BOOK_REPORT_IDENT).Value.ToString();
                bookHierarchy.AddModule(moduletype, identity);
            }


            hierarchy.Add(bookHierarchy.Book);

            // Now configuration
            ReportedAttributeType raConfif = atv.ReportedAttributeList.GetReportedAttributeOfConcept(MSD_BOOK_REPORT_CFG);
            if (raConfif != null)
            {
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(BookConfiguration));
                BookConfig = (BookConfiguration)serializer.Deserialize(new System.IO.StringReader(raConfif.Value.ToString()));
            }
        }
        #endregion


        private TableOfContents GetModuleType(string type)
        {
            TableOfContents toc = TableOfContents.Book;
            try
            {
                toc = (TableOfContents) Enum.Parse(typeof(TableOfContents), type);
            }
            catch (ArgumentException)
            {
                throw new ApplicationException("unknown or null module type detected: " + type != null ? type : "null");
            }
            return toc;
        }
   }

}
